#pragma once

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

using namespace std;

enum
{
    USAGE_ERR = 1,
    SOCKET_ERR,
    CONNECT_ERR
};

class tcpClient
{
public:
    tcpClient(const string& serverip, uint16_t serverport)
    : _sockfd(-1),
      _serverip(serverip),
      _serverport(serverport)
    {}

    void initClient()
    {
        //创建socket文件
        _sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_sockfd == -1)
        {
            cerr << "create socket failed" << endl;
            exit(SOCKET_ERR);
        }
        cout << "create socket success" << endl;
        //绑定ip和port 客户端为了避免端口冲突 让os自动分配ip和port
    }

    void start()
    {
        //与服务器建立链接
        struct sockaddr_in server;
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(_serverip.c_str());
        server.sin_port = htons(_serverport);
        if (connect(_sockfd, (struct sockaddr*)&server, sizeof server) != 0)
        {
            cerr << "connect failed" << endl;
            exit(CONNECT_ERR);
        }
        cout << "connect success" << endl;
        //向服务器发送数据 并接收服务器的处理结果
        string message;
        while (true)
        {
            cout << "Enter# ";
            getline(cin, message);
            /*
            当服务器正在与某一个客户端通信时 另一个客户端也可以与服务器建立链接
            但另一个客户端发来的数据服务器不会立即接收 所以会在write处阻塞等待通信的客户端退出 服务器再正式接收链接创建sock后开始接收数据
            */
            write(_sockfd, message.c_str(), message.size());
            //接收服务器的处理结果
            char buffer[1024];
            int n = read(_sockfd, buffer, sizeof buffer - 1);
            if (n == 0)//服务器关闭 客户端退出
                break;
            if (n > 0)
            {
                buffer[n] = 0;
                cout << buffer << endl;
            }
        }
    }

private:
    int _sockfd;
    string _serverip;
    uint16_t _serverport;
};